package com.my12306.train.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.my12306.common.constant.CommonConstants;
import com.my12306.common.enums.CodeEnum;
import com.my12306.common.model.vo.PageVo;
import com.my12306.common.util.PageUtils;
import com.my12306.common.util.response.ResponseData;
import com.my12306.train.constant.MileageType;
import com.my12306.train.constant.TrainConstant;
import com.my12306.train.dao.TicketDao;
import com.my12306.train.model.entity.*;
import com.my12306.train.model.vo.TicketCarriageVo;
import com.my12306.train.model.vo.TicketVo;
import com.my12306.train.model.vo.TrainNumberVo;
import com.my12306.train.service.*;
import com.my12306.train.utils.TrainUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Service("ticketService")
public class TicketServiceImpl extends ServiceImpl<TicketDao, TicketEntity> implements TicketService {

    @Resource
    private TrainService trainService;
    @Resource
    private SeatService seatService;
    @Resource
    private StationService stationService;
    @Resource
    private TrainScheduleService trainScheduleService;
    @Resource
    private CarriageService carriageService;
    @Resource
    private PlanService planService;
    @Override
    public PageUtils queryTicketPage(PageVo pageVo) {
        pageVo = pageVo.init();
        List<TicketEntity> ticketEntities = this.baseMapper.queryTicketPage(pageVo, CommonConstants.LogicDelete.no_delet.getValue());
        if(ticketEntities != null){
            Integer dataCount = queryTicketCount(pageVo, CommonConstants.LogicDelete.no_delet.getValue());
            System.out.println("数据总量：" + dataCount);
            return PageUtils.build(pageVo, ticketEntities, dataCount);
        }
        return null;
    }

    @Override
    public Integer queryTicketCount(PageVo pageVo, int logicDelete) {
        Integer count = this.baseMapper.queryTicketCount(pageVo, logicDelete);
        return count;
    }

    @Override
    @Transactional
    public ResponseData deleteTicketBatchByIds(List<Long> ticketIds) {
        this.baseMapper.deleteTicketBatchByIds(ticketIds, CommonConstants.LogicDelete.delete.getValue());
        return ResponseData.ok();
    }

    /**
     * 1. 列车类型
     * 2. 所有可售票时间
     * 3.地点(车站)
     * @return
     */
    @Override
    public ResponseData queryTrainNumberParameter() {
       List<String>trainTypes =  this.trainService.queryAllTrainType(CommonConstants.LogicDelete.no_delet.getValue());
       List<Date>dates = this.seatService.queryAllSeatsDate();
        List<StationEntity> stationEntityList = this.stationService.queryAllStation(CommonConstants.LogicDelete.no_delet.getValue());
        List<String> dateVos = dates.stream().map(x -> {
            return getWeek(x);
        }).collect(Collectors.toList());
        return ResponseData.ok().put("dateList",dateVos).put("trainTypes",trainTypes).put("stationList",stationEntityList);
    }

    /**
     * 根据条件检索出那些车次还有车票
     * 1. 从出发站-终点站检索有那些车次经过
     * 2. 车体类型
     * 3.时间点
     * 4.判断每个车次在每个站是否还剩余可售票
     * @param trainNumberVo
     * @return
     */
    @Override
    public ResponseData queryTrainNumber( TrainNumberVo trainNumberVo) {
        //1. 从出发站-终点站检索有那些车次经过
        long fromId = trainNumberVo.getFromId();
        long toId = trainNumberVo.getToId();
        //2. 车体类型
        List<String> trainTypes = trainNumberVo.getTrainTypes();
        String startDate = trainNumberVo.getStartDate();
        /**
         * 获取所有经过出发站和终点站的线路当天的所有该类型车体的车次
         * select  mts.train_code as "车次代码",mts.train_id as "列车id" FROM my_train_schedule mts,my_train mt   where mt.train_id= mts.train_id and  mts.route_id in (select DISTINCT mm.route_id FROM my_mileage mm where mm.logic_delete=1 and mm.from_id in (438964409755860912,43896440072586110) and mm.to_id in (438964409755860912,43896440072586110)) and mts.logic_delete=1 and mt.logic_delete=1
         * and mt.train_type in ("直达特快列车","普通旅客快车")
         */
        //找出符合条件的车次
        List<TrainScheduleEntity> scheduleEntities = this.queryTrainCodeByStationAndTrainType(trainTypes,fromId,toId,CommonConstants.LogicDelete.no_delet.getValue());
        //如果等于null 则无该用户查询的车次
        if (scheduleEntities!=null&&scheduleEntities.size()<=0){
            return ResponseData.ok();
        }


        //生成vo
        List<TicketVo> ticketVos = new ArrayList<>();
        AtomicReference<String> st = new AtomicReference<>("");
        ticketVos = scheduleEntities.stream().map(x->{
            TicketVo ticketVo = new TicketVo();
            BeanUtils.copyProperties(x,ticketVo);
            ticketVo.setTicketCount(0);
            Date startTime = x.getStartTime();
            String dateStr = TrainUtils.getDateStr(startTime, "HH:mm:ss");
            st.set(startDate + " " + dateStr);
            ticketVo.setStartDate(TrainUtils.caclet(st.get(),TrainUtils.formate,0));
            return ticketVo;
        }).collect(Collectors.toList());
        //2.先构建检索票据条件 ： 时间点、车间销售百分比 、销售状态
        /**
         * 先根据所有的车次和时间点和销售状态的最大已经售站点值比较当前起始站是否大于该值如果大于则标标识可售
         * 然后再把所有该可销售的席位信息检索出来进行车次车厢分组最终根据计划进行结果处理显示最终在该车可售的票数
         */

        //根据车次代码和时间和起始站去席位表里找出所有车次代码和时间以及起始站和终点站是改目标的起始站的数据
        //所有车次的线路的所有在该用户检索起始站之前的站点
        Map<String,List<String>> stationMap = new HashMap<>();
        scheduleEntities.stream().forEach(x->{
            List<String> stationByStation = getStationByStation(fromId, x.getTrainCode());
//            log.error("每条线路前置站:"+stationByStation);
            stationMap.put(x.getTrainCode(),stationByStation);
        });
        //根据车次代码和时间点和是否销售条件和该起始站来检索出该用户可购买的票
        String strDate = trainNumberVo.getStartDate();
        //找出车次代码
        List<String> trainCodes = scheduleEntities.stream().map(item -> {
            return item.getTrainCode();
        }).distinct().collect(Collectors.toList());
        StationEntity planFromStation = this.stationService.queryStationById(fromId);
        if (planFromStation==null)  return ResponseData.ok();
        String stationName = planFromStation.getStationName();
        //1.检索出所有以该起始站未售已分配的的席位
        List<SeatEntity> seatEntities = this.seatService.querySeateByStartDateAndTrainCode(strDate,trainCodes , TrainConstant.SEATE_NOT_SOLD,stationName,CommonConstants.LogicDelete.no_delet.getValue());
        ticketVos = ticketVos.stream().map(x->{
           List<SeatEntity> collect = seatEntities.stream().filter(item -> {
               return item.getTrainCode().equals(x.getTrainCode());
           }).collect(Collectors.toList());
//            log.error("===========>获取每个车次该起始站未售的席位:"+collect);
           if (collect!=null&&collect.size()>0) {
//               log.error("===========>每个车次===>:"+x);
               int ticketCount = x.getTicketCount();
               ticketCount = ticketCount + collect.size();
               x.setTicketCount(ticketCount);
           }
           return x;
       }).collect(Collectors.toList());
        //1.1检索出已经销售了的席位票的终点站的状态在该用户检索起始站之前的不受影响的席位
        StationEntity startStation = this.stationService.queryStationById(fromId);
        StationEntity endStation = this.stationService.queryStationById(toId);
        ticketVos = ticketVos.stream().map(x -> {
            List<String> stations = stationMap.get(x.getTrainCode());
            List<SeatEntity> s = this.seatService.querySeateSoledByTrainCodeAndStations(strDate, x.getTrainCode(), stations, TrainConstant.SEATE_SOLD, CommonConstants.LogicDelete.no_delet.getValue());
            if (s!=null&&s.size()>0) {
                int ticketCount = x.getTicketCount();
                ticketCount = ticketCount + s.size();
                x.setTicketCount(ticketCount);
            }

            List<MileageEntity> mileageEntities = queryMileageByStationAndRouteid(fromId, toId, x.getTrainCode());
//            log.error("=========>所有经过的站点起始站和终点站："+mileageEntities);
            if (mileageEntities!=null&&mileageEntities.size()>0){
                x.setStationCount(mileageEntities.size());
                @NotNull String start = x.getStartStation();
                @NotNull String end = x.getEndStation();
                if (start.equals(startStation.getStationName())&&end.equals(endStation.getStationName())){
                    x.setMileageType(MileageType.start_end.getValue());
                }else if (start.equals(startStation.getStationName())&&!end.equals(endStation.getStationName())){
                    x.setMileageType(MileageType.start_after.getValue());
                }else if (!start.equals(startStation.getStationName())&&end.equals(endStation.getStationName())){
                    x.setMileageType(MileageType.after_end.getValue());
                }else if (!start.equals(startStation.getStationName())&&!end.equals(endStation.getStationName())){
                    x.setMileageType(MileageType.after_after.getValue());
                }
//                log.error("============>所有经过的里程表:"+mileageEntities);
                Double aDouble = caclMileage(mileageEntities);
                x.setTotalDistant(aDouble);
                x.setFromId(fromId);
                x.setToId(toId);
            }
            if (startStation!=null) {
                x.setStartStation(startStation.getStationName());
            }
            if (endStation!=null){
                x.setEndStation(endStation.getStationName());
            }

            return x;
        }).collect(Collectors.toList());

        return ResponseData.ok().put("routeTickets",ticketVos);
    }

    /**
     * 计算总的里程
     * @param mileageEntities
     * @return
     */
    public Double caclMileage(List<MileageEntity>mileageEntities){
       return mileageEntities.stream().map(MileageEntity::getTotalMileage).mapToDouble(totalMileage -> totalMileage).sum();
    }
    /**
     * 根据起始站和终点站 找出线路的这两个站和这两个中间的经过站
     */
    public List<MileageEntity> queryMileageByStationAndRouteid(long fromId,long toId,String trainCode){
        if (trainCode!=null){
            List<MileageEntity> mileageEntities =  this.baseMapper.queryRouteStationByTrainCode(trainCode,CommonConstants.LogicDelete.no_delet.getValue());
            mileageEntities = mileageEntities.stream().sorted((x1,x2)->{
              return x1.getParentId().compareTo(x2.getParentId());
            }).distinct().collect(Collectors.toList());
            int from = -1,end = -1;

//            log.error("====queryMileageByStationAndRouteid====>"+mileageEntities);
            for (int i = 0 ;i< mileageEntities.size();i++){
                MileageEntity mileageEntity = mileageEntities.get(i);
                if (mileageEntity.getFromId().equals(fromId)) {
                    from = i;
                }
                if (mileageEntity.getToId().equals(toId)){
                    end = i ;
                }
            }
//            log.error("fromId:"+fromId+",toId:"+toId+",fromIndex:"+from+",toIndex:"+end);
            List<MileageEntity>across = new ArrayList<>();
            if (from!=-1&&end!=-1) {
                for (int i = from; i <= end; i++) {
                    across.add(mileageEntities.get(i));
                }
            }
//            log.error("===========>"+across);
            return across.size()>0?across:null;
        }
        return null;
    }
    /**
     *
     * @param ticketVo
     * @return
     */
    @Override
    public ResponseData queryTicket(TicketVo ticketVo) {
        @NotNull String trainCode = ticketVo.getTrainCode();
        @NotNull String fromStation = ticketVo.getStartStation();
        @NotNull String endStation = ticketVo.getEndStation();
        long routeId = ticketVo.getRouteId();
        Date startDate = ticketVo.getStartDate();
        if (startDate!=null&&trainCode!=null&&fromStation!=null&&endStation!=null){
           //1.先查询该车次的所有车厢
            List<CarriageEntity> carriageEntities = this.carriageService.queryAllCarriageByTrainCode(trainCode,CommonConstants.LogicDelete.no_delet.getValue());
            //1.1 统计每个票种的可售票的数据
            Map<String, TicketCarriageVo>coachSitTypes = new ConcurrentHashMap<>();
            Map<String,String> coachCacles = new HashMap<>();
            List<String> types = carriageEntities.stream().map(x -> {
                return x.getCoachSitType();
            }).distinct().collect(Collectors.toList());
            Map<String, TicketCarriageVo> finalCoachSitTypes1 = coachSitTypes;
            Map<String, String>finalCoachCacles = coachCacles;
            carriageEntities.stream().forEach(x->{
                TicketCarriageVo ticketCarriageVo = new TicketCarriageVo();
                ticketCarriageVo.setTicketCount(0);
                ticketCarriageVo.setCoachSitType(x.getCoachSitType());
                ticketCarriageVo.setCoachNumber(x.getCoachNumber());
                ticketCarriageVo.setShowStatus(x.getShowStatus());
                finalCoachSitTypes1.put(x.getCoachSitType(),ticketCarriageVo);
                finalCoachCacles.put(x.getCoachNumber(),x.getCoachSitType());
            });
            coachSitTypes = finalCoachSitTypes1;
            coachCacles = finalCoachCacles;
            log.error("============>coachCacles:"+coachCacles);
            //1.检索出所有以该起始站未售已分配的的席位
            List<String>trainCodes = new ArrayList<>();
            trainCodes.add(trainCode);
            String dateStr = TrainUtils.getDateStr(startDate,"yyyy-MM-dd HH:mm:ss");
            List<SeatEntity> seatEntities = this.seatService.queryTicketSeateByStartDateAndTrainCode(dateStr,trainCodes , TrainConstant.SEATE_NOT_SOLD,fromStation,CommonConstants.LogicDelete.no_delet.getValue());
            log.error("==========>统计各个票种的未售已分配的数量==:"+coachSitTypes);
            coachSitTypes =  getTicketCount(coachSitTypes,coachCacles,seatEntities);

            /**
             * 如果起始站是线路的起始站就不用查之前的站点了
             */
            if (!(ticketVo.getMileageType().equals(MileageType.start_end.getValue())||ticketVo.getMileageType().equals(MileageType.start_after.getValue()))) {
                /**
                 * 获取起始站之前的站点
                 */
                List<String> stations = getStationByStation(ticketVo.getFromId(), trainCode);
                if (stations != null && stations.size() > 0) {
                    String dateStr1 = TrainUtils.getDateStr(startDate,"yyyy-MM-dd HH:mm:ss");
                    log.debug("==============>所有起始站之前的站点：" + stations);
                    List<SeatEntity> seatList = this.seatService.queryTicketSeate(dateStr1, trainCode, stations, TrainConstant.SEATE_SOLD, CommonConstants.LogicDelete.no_delet.getValue());
                    log.error("=========》已经购买的席位票："+seatList);
                    log.error("已经购买的席位票计算：");
                    coachSitTypes =  getTicketCount(coachSitTypes,coachCacles,seatList);
                }
            }
            List<TicketCarriageVo> carriageVoList = new ArrayList<>();
            Map<String, TicketCarriageVo> finalCoachSitTypes = coachSitTypes;
            types.stream().forEach(type->{
                TicketCarriageVo ticketCarriageVo = finalCoachSitTypes.get(type);
                carriageVoList.add(ticketCarriageVo);
            });
            return ResponseData.ok().put("coachSitTypes",carriageVoList);
        }
        return ResponseData.fail(CodeEnum.FAIL.getCode(),"购票失败！原因：系统数据异常！请等待修复后再进行购票！");
    }
    private  Map<String, TicketCarriageVo> getTicketCount(   Map<String, TicketCarriageVo>coachSitTypes, Map<String,String> coachCacles, List<SeatEntity> seatList){
        if (seatList!=null&&seatList.size()>0) {
            log.error("============>coachCacles:"+coachCacles);

            for (int i = 0; i < seatList.size(); i++) {
                SeatEntity seatEntity = seatList.get(i);
                String coachSitType = coachCacles.get(seatEntity.getCoachNumber());
                if (coachSitType!=null) {
                    TicketCarriageVo ticketCarriageVo = coachSitTypes.get(coachSitType);
                    int ticketCount = ticketCarriageVo.getTicketCount();
                    ticketCarriageVo.setTicketCount(ticketCount + 1);
                    coachSitTypes.put(coachSitType, ticketCarriageVo);
                }
            }
        }
        return coachSitTypes;
    }


    /**
     * 根据起始站和车次代码找出该车站前面的车站，可以判断已经买票的席位是否对后续有影响
     * @param fromId
     * @param trainCode
     * @return
     */
    @Override
    public List<String>getStationByStation(Long fromId,String trainCode){
        if (fromId!=null&&trainCode!=null){
            List<MileageEntity> mileageEntities =  this.baseMapper.queryRouteStationByTrainCode(trainCode,CommonConstants.LogicDelete.no_delet.getValue());
            MileageEntity planMileage = new MileageEntity();
            for (MileageEntity mileageEntity : mileageEntities) {
                //判断是否存在该起始站
                if (mileageEntity.getFromId().equals(fromId)) {
                    planMileage=mileageEntity;
                    break;
                }
            }
            //如果没找到计划中起始站则则返回
            if (planMileage==null)return null;
            List<MileageEntity> sortMileages = mileageEntities.stream().sorted((x1, x2) -> {
                return x1.getParentId().compareTo(x2.getParentId());
            }).distinct().collect(Collectors.toList());
            System.out.println(sortMileages);
            List<String> stations = new ArrayList<>();
//            log.error("fromName:"+planMileage);
            for (int i = 0 ; i <mileageEntities.size();i++){
                MileageEntity mileageEntity = mileageEntities.get(i);
                long parentId = mileageEntity.getParentId();

                if (parentId==-1) {
//                    log.error("====");
                }else{
                    log.error("+"+mileageEntity.getFromName().equals(planMileage.getFromName()));
                    if (mileageEntity.getFromName().equals(planMileage.getFromName())) {
                        break;
                    } else {
//                        log.error("item=========>"+mileageEntity);
                            stations.add(mileageEntity.getToName());
                           stations.add(mileageEntity.getFromName());
                    }
                }
            }
//            log.error("===========>所有的起始站之前的站点："+stations);
            if (stations!=null&&stations.size()>0){
                return stations;
            }
        }
        return null;
    }

    private List<TrainScheduleEntity> queryTrainCodeByStationAndTrainType(List<String> trainTypes, long fromId, long toId, int logicDelete) {
        if (trainTypes!=null&&trainTypes.size()>0) {
            return this.baseMapper.queryTrainByStationAndTrainType(trainTypes, fromId, toId, logicDelete);
        }else{
            return this.baseMapper.queryTrainByStationAndTrainType(null, fromId, toId, logicDelete);
        }
    }

    private static String  getWeek(Date date){
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = format.format(date);
//        DayOfWeek dayOfWeek = LocalDateTime.parse(format1, TrainUtils.formate).getDayOfWeek();
//        return dayOfWeek.getDisplayName(TextStyle.FULL,Locale.CHINA);
        return dateStr;
    }
}
